package net.forsuber.publish;

import net.forsuber.data.Record;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.cookie.CookieSpec;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author lzapletal
 */
public class DrupalArticlePublisher implements Publisher {

    private static final Log LOG = LogFactory.getLog(DrupalArticlePublisher.class);

    private String site = "www.rofled.com";

    private int port = 80;

    private HttpClient client;

    private String username;

    private String password;

    private String bodyPre, bodyPost;

    public void open() {
        client = new HttpClient();
    }

    protected void log(String s) {
        LOG.info(s);
    }

    public void publish(Record record) throws PublisherException {
        if (record == null)
            throw new IllegalArgumentException("Record can`t be null");

        try {
            client.getHostConfiguration().setHost(site, port, "http");
            client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
            CookieSpec cookiespec = CookiePolicy.getDefaultSpec();

            // get the cookie
            GetMethod authget = new GetMethod("/");
            authget.setFollowRedirects(true);
            client.executeMethod(authget);
            log("Getting " + getSite() + ":" + getPort() + "/ with result: " + authget.getStatusLine().toString());
            checkResponseCode(authget, HttpStatus.SC_OK);
            logCookies(cookiespec);
            //log(authget.getResponseBodyAsString());
            authget.releaseConnection();

            // login
            log("Logging as '" + getUsername() + "' with password '" + getPassword() + "'");
            PostMethod authpost = new PostMethod("/node?destination=node");
            NameValuePair form_id = new NameValuePair("form_id", "user_login_block");
            NameValuePair action = new NameValuePair("name", getUsername());
            NameValuePair url = new NameValuePair("pass", getPassword());
            authpost.setRequestBody(new NameValuePair[]{action, url, form_id});
            client.executeMethod(authpost);
            checkResponseCode(authpost, HttpStatus.SC_OK);
            logCookies(cookiespec);
            //log(authpost.getResponseBodyAsString());
            authpost.releaseConnection();

            // get the form (token)
            authget = new GetMethod("/node/add/clanek");
            authget.setFollowRedirects(true);
            client.executeMethod(authget);
            log("Getting " + getSite() + ":" + getPort() + "/ with result: " + authget.getStatusLine().toString());
            checkResponseCode(authget, HttpStatus.SC_OK);
            logCookies(cookiespec);
            //log(authget.getResponseBodyAsString());
            Pattern p = Pattern.compile("value=\"[a-f0-9]{32}\"");
            Matcher m = p.matcher(authget.getResponseBodyAsString());
            String token;
            if (m.find()) {
                token = authget.getResponseBodyAsString().substring(m.start() + 7, m.end() - 1);
            } else {
                throw new PublisherException("Cannot parse form security token");
            }
            log("Security token is: '" + token + "'");
            authget.releaseConnection();

            // do the post
            log("Posting '" + record.getTitle() + "'");
            authpost = new PostMethod("/node/add/clanek");
            form_id = new NameValuePair("form_id", "clanek_node_form");
            NameValuePair form_token = new NameValuePair("form_token", token);
            NameValuePair title = new NameValuePair("title", record.getTitle());
            NameValuePair tax = new NameValuePair("taxonomy[tags][1]", join(record.getAadditional()));
            NameValuePair body = new NameValuePair("body", getBodyPre() + record.getBody() + getBodyPost());
            NameValuePair op = new NameValuePair("op", "Poslat");
            NameValuePair format = new NameValuePair("format", "3");
            NameValuePair changed = new NameValuePair("changed", "");
            authpost.setRequestBody(new NameValuePair[]{title, form_id, form_token, body, tax, format, changed, op});
            client.executeMethod(authpost);
            checkResponseCode(authpost, HttpStatus.SC_MOVED_TEMPORARILY);
            logCookies(cookiespec);
            authpost.releaseConnection();

            // logout
            authget = new GetMethod("/logout");
            client.executeMethod(authget);
            log("Logout with result: " + authget.getStatusLine().toString());
            logCookies(cookiespec);
            authget.releaseConnection();

            // done
        } catch (Exception e) {
            throw new PublisherException(e);
        }
    }

    private void logCookies(CookieSpec cookiespec) {
        StringBuilder sb = new StringBuilder();

        // See if we got any cookies
        Cookie[] initcookies = cookiespec.match(
                site, port, "/", false, client.getState().getCookies());
        sb.append("Cookies:");
        if (initcookies.length == 0) {
            sb.append(" None");
        } else {
            for (Cookie initcooky : initcookies) {
                sb.append(" ").append(initcooky.toString());
            }
        }
        LOG.debug(sb.toString());
    }

    public static String join(String[] s) {
        StringBuffer buffer = new StringBuffer();
        for (String str : s) {
            buffer.append(str).append(", ");
        }
        return buffer.toString();
    }

    private void checkResponseCode(HttpMethodBase authpost, int code) throws PublisherException {
        if (authpost.getStatusCode() != code)
            log("The response code was not 200, it was: " + authpost.getStatusLine().toString());
    }

    public void close() {
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getSite() {
        return site;
    }

    public void setSite(String site) {
        this.site = site;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getBodyPre() {
        if (bodyPre == null)
            return "";
        else
            return bodyPre;
    }

    public void setBodyPre(String bodyPre) {
        this.bodyPre = bodyPre;
    }

    public String getBodyPost() {
        if (bodyPost == null)
            return "";
        else
            return bodyPost;
    }

    public void setBodyPost(String bodyPost) {
        this.bodyPost = bodyPost;
    }
}
